import { on, CESIUM_VIEWER_INITIALIZATION } from '../../utils/EventBus.js'
import * as Cesium from 'cesium'
import { MixedLayer } from '../../utils/MixedLayer'
import { DomEntity } from '../../utils/DomEntity.js'
import { SingleDebouncedCesiumMouseMove } from '../../components/cesium/screen-event/DebouncedCesiumMouseMove.js'
import { repositoryTableData } from '../../views/left-right/RepositoryInfo/RepositoryTable.vue'
import { CssMaskEffect } from './CssMaskEffect.js'
import { toogleScreenSpaceCameraController } from '../../components/cesium/camera.js'
import { toggleMapControls } from '../three-scene/toggleMapControls.js'
import './repository.scss'

const pageDuration = 1000

on(CESIUM_VIEWER_INITIALIZATION, () => {
    cesiumViewer.scene.screenSpaceCameraController.enableCollisionDetection = false

    // todo 不知道有什么影响，先试试吧，有时间看一下源码
    cesiumViewer.screenSpaceEventHandler.destroy()

    const singleDebouncedCesiumMouseMove = new SingleDebouncedCesiumMouseMove(
        cesiumViewer,
        100
    )
    singleDebouncedCesiumMouseMove.addCallback((pickedObject) => {
        if (!Repository.instance) return
        const { domEntities } = Repository.instance.ml

        domEntities.forEach((element) => {
            element.rootDom.firstElementChild.classList.remove('show')
        })

        if (
            Cesium.defined(pickedObject) &&
            pickedObject.id instanceof Cesium.Entity
        ) {
            const domEntity = domEntities.find(
                (element) => element._id === pickedObject.id.id
            )
            if (domEntity) {
                domEntity.rootDom.firstElementChild.classList.add('show')
            }
        }
    })

    const trw = document.querySelector('.three-root-wrapper')
    trw.addEventListener('dblclick', (ev) => {
        // if (ev.ctrlKey) {
        toggleMapControls(false)
        toggleCesium(true)
        toggleThree(false)
        flyToPoints(window.tempCartesian3Array, 1.5).then(() => {
            toogleScreenSpaceCameraController(true)
        })
        // }
    })
})

export class Repository {
    static instance = null
    constructor() {
        this.ml = new MixedLayer()
        this.bindCameraEvent()
        this.bindEventHandler()
    }
    destroy() {
        this.ml.destroy()
    }
    create(data) {
        const pinBuilder = new Cesium.PinBuilder()
        data.forEach(({ name, cartesian3 }) => {
            Promise.resolve(
                pinBuilder.fromMakiIconId(
                    'warehouse',
                    Cesium.Color.ROYALBLUE,
                    48
                )
            ).then((canvas) => {
                this.ml.dataSource.entities.add({
                    id: name,
                    name,
                    position: cartesian3,
                    billboard: {
                        disableDepthTestDistance: Number.POSITIVE_INFINITY,
                        image: canvas.toDataURL(),
                        verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
                    },
                    properties: new Cesium.PropertyBag({
                        type: 'repository',
                    }),
                })

                this.ml.domEntities.push(
                    new DomEntity({
                        parentDom: document.querySelector('#cesiumContainer'),
                        id: name,
                        position: cartesian3,
                        html: `
    <div class="repository-name-wrapper">
        <div class="repository-name">
            ${name}
        </div>
    </div>
              `,
                        pixelOffset: new Cesium.Cartesian2(0, -50),
                        horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
                        verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
                    })
                )
            })
        })
        return this
    }

    bindCameraEvent() {
        const depthFit = () => {
            const pitchDegree = Cesium.Math.toDegrees(cesiumViewer.camera.pitch)
            if (pitchDegree < -50) {
                this.ml.dataSource.entities.values.forEach((entity) => {
                    entity.billboard.disableDepthTestDistance =
                        Number.POSITIVE_INFINITY
                })
            } else {
                this.ml.dataSource.entities.values.forEach((entity) => {
                    entity.billboard.disableDepthTestDistance = 0
                })
            }
        }

        const removeMoveEndCallbak =
            cesiumViewer.camera.moveEnd.addEventListener(depthFit)
        const removeChangedCallbak =
            cesiumViewer.camera.changed.addEventListener(depthFit)
        this.ml.destroyCallback.push(removeMoveEndCallbak, removeChangedCallbak)
    }

    bindEventHandler() {
        const handler = new Cesium.ScreenSpaceEventHandler(
            cesiumViewer.scene.canvas
        )
        handler.setInputAction((movement) => {
            const pickedObject = cesiumViewer.scene.pick(movement.position)
            if (Cesium.defined(pickedObject)) {
                if (
                    Cesium.defined(pickedObject) &&
                    pickedObject.id instanceof Cesium.Entity
                ) {
                    this.popBox(pickedObject.id)
                }
            }
        }, Cesium.ScreenSpaceEventType.LEFT_CLICK)
    }

    popBox(entity) {
        const data = repositoryTableData.find((item) => item.name === entity.id)
        const cssMaskEffect = new CssMaskEffect()
        this.ml.domEntities.push(
            new DomEntity({
                parentDom: document.querySelector('#cesiumContainer'),
                id: 'pop-box_' + entity.id,
                position: entity.position.getValue(),
                html: cssMaskEffect.appendHtml(getPopBox(data, entity.id)).html,
                // pixelOffset: new Cesium.Cartesian2(0, -50),
                horizontalOrigin: Cesium.HorizontalOrigin.LEFT,
                verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
            })
        )
        cssMaskEffect.show()

        // {
        //     "name": "库室1",
        //     "oil": "0.1%",
        //     "oxygen": "20.9%",
        //     "temperature": "25°C",
        //     "humidity": "50%",
        //     "door": "关闭",
        //     "coord": {
        //         "longitude": 2.024726076130041,
        //         "latitude": 0.6975419291686485,
        //         "height": 323.3668963019752
        //     },
        //     "cartographicArray": [
        //         2.024726076130041,
        //         0.6975419291686485,
        //         323.3668963019752
        //     ],
        //     "cartesian3": {
        //         "x": -2146621.552876917,
        //         "y": 4399616.737382552,
        //         "z": 4075318.366776635
        //     }
        // }
    }
}

function getPopBox(data, id) {
    const style = {
        table: `width: max-content;
            padding: 20px 20px 10px;
box-shadow: 0 8px 32px 0 rgba( 31, 38, 135, 0.37 );
backdrop-filter: blur( 4px );
-webkit-backdrop-filter: blur( 4px );
color: #fff;
            `,
        tableWrapper: `
    position: relatetive;
   background: linear-gradient(45deg, rgba(4, 55, 106, 0.95) 45%, rgba(4, 55, 106, 0.4) 100%);
border: 1px solid rgba( 255, 255, 255, 0.58 );
            `,
        closeBtn: `
    pointer-events: auto;
    position: absolute;
    top: 0px;
    right: 10px;
    color: white;
    cursor: pointer;
    font-size: 20px;
    z-index:1;
    `,
        modelBtn: `
    width:80%;
    background: transparent;
    color: #fff;
    display: block;
    margin-inline: auto;
    border-color: #fff;
    cursor:pointer;
    pointer-events: auto;
    margin-block: 6px;`,
    }
    const fields = ['name', 'oil', 'oxygen', 'temperature', 'humidity', 'door']
    const trString = fields.reduce((acc, field) => {
        const value = data[field]
        return (
            acc +
            `
      <tr>
        <td>${field}</td>
        <td>:</td>
        <td>${value}</td>
      </tr>
    `
        )
    }, '')
    const htmlString = `
  <div style="${style.tableWrapper}">
    <div style="${style.closeBtn}" close-btn>X</div>
    <table style="${style.table}">${trString}</table>
    <button style="${style.modelBtn}" check-btn>查看库室场景</button>
  </div>
  `

    const parser = new DOMParser()
    const doc = parser.parseFromString(htmlString, 'text/html')
    const destroyPopbox = () => {
        const index = Repository.instance.ml.domEntities.findIndex(
            (element) => element._id === 'pop-box_' + id
        )
        if (index > -1) {
            Repository.instance.ml.domEntities.splice(index, 1)[0].destroy()
        }
    }

    const closeBtn = doc.querySelector('[close-btn]')
    closeBtn.addEventListener('click', () => {
        destroyPopbox()
    })

    const checkBtn = doc.querySelector('[check-btn]')
    checkBtn.addEventListener('click', () => {
        destroyPopbox()
        toggleThree(true)
        toogleScreenSpaceCameraController(false)
        toggleCesium(false)
        flyToThree(data.cartographicArray).then(() => {
            toggleMapControls(
                true,
                Cesium.Cartesian3.pack(data.cartesian3, Array(3))
            )
        })
    })

    return doc.body.firstChild
}

function flyToThree(cartographicArray, distance = 2000) {
    return new Promise((resolve) => {
        const [lon, lat, height] = cartographicArray
        const { heading, pitch } = cesiumViewer.camera

        // todo
        const bs = new Cesium.BoundingSphere(
            Cesium.Cartesian3.fromRadians(lon, lat, height),
            distance
        )

        cesiumViewer.camera.flyToBoundingSphere(bs, {
            duration: 1.5,
            offset: new Cesium.HeadingPitchRange(heading, pitch, bs.radius),
            complete: () => {
                resolve()
            },
        })
    })
}

export function flyToPoints(cartesian3Array, duration = 0) {
    return new Promise((resolve) => {
        const bs = Cesium.BoundingSphere.fromPoints(cartesian3Array)
        cesiumViewer.camera.flyToBoundingSphere(bs, {
            duration,
            offset: new Cesium.HeadingPitchRange(0, -Math.PI / 6, 0),
            complete: () => {
                resolve()
            },
        })
    })
}

function toggleCesium(visible) {
    const { canvas } = window.cesiumViewer
    return new Promise((resolve) => {
        const cesiumAnimation = new Animation(
            new KeyframeEffect(
                canvas,
                [{ opacity: 1 }, { opacity: 0.9, offset: 0.3 }, { opacity: 1 }],
                {
                    duration: pageDuration,
                    fill: 'both',
                }
            )
        )
        cesiumAnimation.playbackRate = visible ? 1 : -1
        cesiumAnimation.play()
        cesiumAnimation.onfinish = () => {
            cesiumAnimation.commitStyles()
            resolve()
        }
    })
}

function toggleThree(visible) {
    const {
        renderer: { domElement },
    } = window.threeScene.my
    return new Promise((resolve) => {
        const threeAnimation = new Animation(
            new KeyframeEffect(
                domElement.parentElement,
                [
                    { opacity: 0.0 },
                    { opacity: 0.3, offset: 0.7 },
                    { opacity: 1 },
                ],
                {
                    duration: pageDuration,
                    fill: 'both',
                }
            )
        )
        threeAnimation.playbackRate = visible ? 1 : -1
        threeAnimation.play()
        threeAnimation.onfinish = () => {
            threeAnimation.commitStyles()
            resolve()
        }
    })
}
